import sys
import os
# 获取项目根目录的绝对路径
project_root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
# 将项目根目录添加到 sys.path
sys.path.append(project_root)
import logging
import json
import faiss
import httpx
import numpy as np
from openai import OpenAI
from src.utils.llm import get_llm_response
from src.utils.config.global_config import param_config
from src.utils.config.app_config import AppInterface
from src.utils.shell_execute import SshClient
from src.performance_analyzer.performance_analyzer import PerformanceAnalyzer

from src.performance_collector.metric_collector import MetricCollector


from src.performance_optimizer.param_knowledge import ParamKnowledge
from typing import Dict
from enum import Enum


embedding_client = OpenAI(
    base_url='https://api.chatanywhere.tech/v1',
    api_key='sk-H6MolvD7JDUtji9cXmaBQhqV7fwJZfL2rgt2wGhAJqTWKFuS',
    http_client=httpx.Client(verify=False)
)

def generate_embeddings(text: str, model="text-embedding-ada-002"):
    response = embedding_client.embeddings.create(input=text, model=model)
    return response.data[0].embedding


def match_report(report_text: str, all_params: list[str], top_k: int = 20):

    INDEX_PATH = os.path.abspath(
        os.path.join(os.path.dirname(__file__), "..", "knowledge_base", "knob_index")
    )
    report_str = ""
    for k, v in report_text.items():
        report_str += f"[{k}]\n{v.strip()}\n\n"
    # 加载索引和名称
    index = faiss.read_index('./src/knowledge_base/knob_index/system.index')

    with open(os.path.join(INDEX_PATH, 'system.json'), "r") as f:
        param_names = json.load(f)
    param_names_set = set(param_names)

    # 查询嵌入
    query_vec = np.array([generate_embeddings(report_str[0:1500])]).astype("float32")


    # 搜索 top_k 个最近邻（返回的是索引号）
    _, top_indices = index.search(query_vec, top_k)
    top_indices = top_indices[0]  # 取第一行

    # 根据索引号拿到对应的参数名
    top_params = {param_names[i] for i in top_indices}

    # 在全集中过滤：只保留出现在 top_params 里的
    matched_params = [p for p in all_params if p in top_params]
    # 额外保留：全集中那些“未出现在索引中”的参数（如应用参数）
    unmatched_app_params = [p for p in all_params if p not in param_names_set]


    final_params = matched_params + unmatched_app_params

    print("RAG匹配参数（在索引中命中）:", matched_params)
    print("附加保留参数（应用参数）:", unmatched_app_params)

    return final_params


# 配置日志
logging.basicConfig(
    level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s"
)

class PerformanceMetric(Enum):
    QPS = "QPS：每秒查询请求数（Queries Per Second），单位：次/秒"
    RT = "RT：响应时间（Response Time），即从请求发出到收到响应的时间，单位：毫秒"
    THROUGHPUT = "吞吐量：系统在单位时间内处理的请求数量或数据量，单位：请求数/秒 或 字节/秒"
    CPU_USAGE = "CPU利用率：CPU 在单位时间内被使用的比例，单位：%"
    MEMORY_USAGE = "内存利用率：内存被使用的比例，单位：%"
    DISK_USAGE = "磁盘利用率：磁盘被使用的比例，单位：%"
    NETWORK_TRAFFIC = "网络流量：网络接口在单位时间内接收和发送的流量总和，单位：KB/s"


def json_repair(
    json_str: str
) -> Dict:
    json_start = json_str.find('{')
    json_end = json_str.rfind('}') + 1
    json_str = json_str[json_start:json_end]
    try:
        json_data = json.loads(json_str)
    except json.decoder.JSONDecodeError as e:
        #raise RuntimeError(f"failed to parse json, raw json_str is {json_str}")
        return {}
    return json_data

class ParamRecommender:

    def __init__(
        self,
        service_name: str,
        slo_goal: float,
        performance_metric: PerformanceMetric,
        static_profile: str,
        performance_analysis_report: str,
        chunk_size=20,
        enable_system_params=True,
        ssh_client=None,
    ):
        # 待调优app名称
        self.service_name = service_name
        # 业务性能调优目标，指标提升百分比
        self.slo_goal = slo_goal
        # 性能指标介绍
        self.performance_metric = performance_metric
        # 静态指标
        self.static_profile = "\n".join(f"{k}: {v}" for k, v in static_profile.items())
        # 可调参数知识库，用于给大模型描述应用参数背景知识
        self.param_knowledge = ParamKnowledge(ssh_client)
        self.all_params = self.param_knowledge.get_params(service_name)
        self.ssh_client = ssh_client
        self.rag_params = match_report(performance_analysis_report,self.all_params)
        self.params_set = self.param_knowledge.describe_param_background_knob(
            service_name, self.rag_params
        )
        self.chunk_size = chunk_size
        self.performance_analysis_report = performance_analysis_report

    def _process_chunk(self, history_result, cur_params_set):
        recommend_prompt = f"""
# CONTEXT # 
本次性能优化的目标为：
性能指标为{self.performance_metric.name}, 该指标的含义为：{self.performance_metric.value}，目标是提升{self.slo_goal:.2%}
性能分析报告：
{self.performance_analysis_report}
你可以分析的参数有：
{",".join(cur_params_set)}
# OBJECTIVE #
你是一个专业的系统运维专家,当前性能指标未达到预期，请你基于以上性能分析报告分析有哪些调优思路。
# Tone #
你应该尽可能秉承严肃、认真、严谨的态度
# AUDIENCE #
你的答案将会是其他系统运维专家的重要参考意见，请认真思考后给出你的答案。
"""
        optimized_idea = get_llm_response(recommend_prompt)
        print(optimized_idea)
        recommended_params = self.recommend(
            history_result, optimized_idea, cur_params_set
        )
        recommended_params_set = json_repair(recommended_params)

        result = {}
        for param_name, param_value in recommended_params_set.items():
            if param_name in self.all_params:
                result[param_name] = param_value
        return result

    def run(self, history_result):
        resultset = {}
        print("开始执行 run 方法，参数集长度为：", len(self.params_set))

        for i in range(0, len(self.params_set), self.chunk_size):
            cur_params_set = self.params_set[i : i + self.chunk_size]
            print(f"正在处理第 {i // self.chunk_size + 1} 个参数子集，子集大小为：", len(cur_params_set))

            # 直接调用 _process_chunk 方法处理当前参数集
            try:
                chunk_result = self._process_chunk(history_result, cur_params_set)
                print("当前参数子集处理完成，结果为：", chunk_result)
            except Exception as e:
                print("处理当前参数子集时发生异常：", e)
                raise

            # 将当前参数子集的处理结果更新到结果集中
            resultset.update(chunk_result)
            print("已更新结果集，当前结果集为：", resultset)

        print("所有参数子集处理完毕，最终结果为：", resultset)
        return resultset

    def recommend(self, history_result, optimization_idea, cur_params_set):
        history_result = str(history_result[-1]) if history_result else "无"
        params_set_str = "\n".join(cur_params_set)
        prompt = f"""
你是一个专业的系统运维专家,当前性能指标未达到预期，请你基于以下调优思路、当前环境的配置信息、可调整参数，选出可调整参数值。
请尽量精简描述，将终点需要调整的方向输出出来，不需要总结观点，对性能无影响的也不要输出。
当前环境的配置信息有：
{self.static_profile}
以下是历史调优的信息，历史调优修改了如下参数，你可以参考如下历史调优信息来反思可以可以改进的点: 
{history_result}
调优思路是：
{optimization_idea}
你可以调整的参数是：
{params_set_str}
请以json格式回答问题，key为可调参数名称，请根据上述的环境配置信息给出可调整的参数，若参数不相关则不要给出
value是可调参数的推荐取值，请根据上面的环境配置信息给出合理的具体取值，请仔细确认各个值是否可以被使用，避免设置后应用无法启动。
请注意若参数取值为数字类型，默认的单位为字节，请注意单位换算；若数字后面跟了单位，请使用字符串表示。请注意不要出现小数的格式，推荐参数无论是否带单位最好使用整数。
请勿给出除了json以外其他的回复,切勿增加注释。
"""
        response = get_llm_response(prompt)
        return response

    
    
